package com.svndiffdoc;

import java.io.BufferedReader;
import java.io.Console;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringWriter;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;

public class CommandLineParser {
    public static final String OPTION_OLD = "old";
    public static final String OPTION_NEW = "new";
    public static final String OPTION_USERNAME = "username";
    public static final String OPTION_USERNAME_PROMPT = "username-prompt";
    public static final String OPTION_PASSWORD = "password";
    public static final String OPTION_PASSWORD_PROMPT = "password-prompt";

    private static final String helpCommandName = "java -jar SvnDiffDoc.jar";
    private static final String helpCommandLineSyntax = helpCommandName + " --old url[@rev] --new url[@rev] [--username <user>] [--password <password>]";
    private static final String helpHeader = "command line arguments:";
    private static final String helpUsageExamples = "\nUsage examples:\n" +
            helpCommandName + " --" + OPTION_OLD + " https://server/svn/Repo/branch   --" + OPTION_NEW + " https://server/svn/Repo/trunc\n" +
            helpCommandName + " --" + OPTION_OLD + " https://server/svn/Repo/branch   --" + OPTION_NEW + " https://server/svn/Repo/trunc   --" + OPTION_USERNAME + " john\n" +
            helpCommandName + " --" + OPTION_OLD + " https://server/svn/Repo/branch@1 --" + OPTION_NEW + " https://server/svn/Repo/trunc@2 --" + OPTION_USERNAME + " john --" + OPTION_PASSWORD + " secret\n" +
            helpCommandName + " --" + OPTION_OLD + " https://server/svn/Repo/branch@1 --" + OPTION_NEW + " https://server/svn/Repo/trunc@2 --" + OPTION_USERNAME_PROMPT + " --" + OPTION_PASSWORD_PROMPT + "\n";

    private final Options options;
    private final HelpFormatter helpFormatter;
    //
    private String oldRepositoryUrlWithOptionalRevision;
    private String newRepositoryUrlWithOptionalRevision;
    private String username;
    private String password;

    public CommandLineParser(String[] arguments) throws ParseException {
        options = new Options();
        options.addOption(null, OPTION_OLD, true, "old repository url with optional revision number (URL[@REV])");
        options.addOption(null, OPTION_NEW, true, "new repository url with optional revision number (URL[@REV])");
        options.addOption(null, OPTION_PASSWORD, true, "optional user password");
        options.addOption(null, OPTION_PASSWORD_PROMPT, false, "optional user password prompt");
        options.addOption(null, OPTION_USERNAME, true, "optional user name");
        options.addOption(null, OPTION_USERNAME_PROMPT, false, "optional user name prompt");

        helpFormatter = new HelpFormatter();

        try {
            PosixParser parser = new PosixParser();
            CommandLine commandLine = parser.parse(options, arguments);

            if (!commandLine.hasOption(OPTION_OLD)) {
                throw new ParseException("Missing required argument: --" + OPTION_OLD + " url[@rev]");
            }

            if (!commandLine.hasOption(OPTION_NEW)) {
                throw new ParseException("Missing required argument: --" + OPTION_NEW + " url[@rev]");
            }

            oldRepositoryUrlWithOptionalRevision = commandLine.getOptionValue(CommandLineParser.OPTION_OLD);
            newRepositoryUrlWithOptionalRevision = commandLine.getOptionValue(CommandLineParser.OPTION_NEW);

            if (commandLine.hasOption(OPTION_USERNAME)) {
                username = commandLine.getOptionValue(CommandLineParser.OPTION_USERNAME);
            }

            if (commandLine.hasOption(OPTION_USERNAME_PROMPT)) {
                try {
                    Console console = System.console();
                    if (console != null) {
                        username = new String(console.readLine("[%s] ", "Username:"));
                    }
                    else {
                        System.out.print("[Username:] ");
                        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
                        username = reader.readLine();
                    }
                } catch (IOException e) {
                    throw new ParseException(e.getMessage());
                }
            }

            if (commandLine.hasOption(OPTION_PASSWORD)) {
                password = commandLine.getOptionValue(CommandLineParser.OPTION_PASSWORD);
            }

            if (commandLine.hasOption(OPTION_PASSWORD_PROMPT)) {
                try {
                    Console console = System.console();
                    if (console != null) {
                        password = new String(console.readPassword("[%s] ", "Password:"));
                    }
                    else {
                        System.out.print("[Password:] ");
                        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
                        password = reader.readLine();
                    }
                } catch (IOException e) {
                    throw new ParseException(e.getMessage());
                }
            }

        }
        catch (ParseException e) {
            StringWriter stringWriter = new StringWriter();
            PrintWriter printWriter = new PrintWriter(stringWriter);
            printWriter.println(e.getLocalizedMessage());
            helpFormatter.printHelp(printWriter, 140, helpCommandLineSyntax, helpHeader, options, 1, 3, helpUsageExamples, false);
            printWriter.flush();
            throw new ParseException(stringWriter.toString());
        }
    }

    public String getOldRepositoryUrlWithOptionalRevision() {
        return oldRepositoryUrlWithOptionalRevision;
    }

    public void setOldRepositoryUrlWithOptionalRevision(String oldRepositoryUrlWithOptionalRevision) {
        this.oldRepositoryUrlWithOptionalRevision = oldRepositoryUrlWithOptionalRevision;
    }

    public String getNewRepositoryUrlWithOptionalRevision() {
        return newRepositoryUrlWithOptionalRevision;
    }

    public void setNewRepositoryUrlWithOptionalRevision(String newRepositoryUrlWithOptionalRevision) {
        this.newRepositoryUrlWithOptionalRevision = newRepositoryUrlWithOptionalRevision;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

}
